home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-05-22 | 50.8 KB | 2,260 lines |
- Newsgroups: comp.sources.misc
- From: Byron Rakitzis <byron@archone.tamu.edu>
- Subject: v20i010: rc - A Plan 9 shell reimplementation, Part01/04
- Message-ID: <1991May22.154142.3038@sparky.IMD.Sterling.COM>
- Date: Wed, 22 May 1991 15:41:42 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Md4-Signature: b408abcee26289e688696dd726246581
-
- Submitted-by: Byron Rakitzis <byron@archone.tamu.edu>
- Posting-number: Volume 20, Issue 10
- Archive-name: rc/part01
-
- rc is a command interpreter and programming language similar
- to sh(1). It is based on the AT&T plan 9 shell of the same
- name. The shell offers a C-like syntax (much more so than
- the C shell), and a powerful mechanism for manipulating
- variables. It is reasonably small and reasonably fast,
- especially when compared to contemporary shells. Its use is
- intended to be interactive, but the language lends itself
- well to scripts.
-
- This shell was written by me, Byron Rakitzis, but kudos go to Paul
- Haahr for letting me know what a shell should do and for contributing
- certain bits and pieces to rc (notably the limits code, most of which.c
- and the backquote redirection code), and to Hugh Redelmeier for running
- rc through his fussy ANSI compiler and thereby provoking interesting
- discussions about portability, and also for providing many valuable
- suggestions for improving rc's code in general. Finally, many thanks
- go to David Sanderson, for reworking the man page to format well with
- troff, and for providing many suggestions both for rc and its man page.
-
- Of course, without Tom Duff's design of the original rc, I could not
- have written this shell (though I probably would have written *a*
- shell). Almost of all of the features, with minor exceptions, have been
- implemented as described in the Unix v10 manuals. Hats off to td for
- designing a C-like, minimal but very useful shell.
-
- Byron Rakitzis
- --------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: README builtins.c hash.h rc.1
- # Wrapped by kent@sparky on Wed May 22 01:21:49 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 4)."'
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(3564 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XThis is release 1.0 of rc.
- X
- XRead COPYRIGHT for copying information. All files are
- X
- XCopyright 1991, Byron Rakitzis.
- X
- X------ Compiling rc:
- X
- XTo compile rc, you need an ANSI compiler like gcc. Some compilers which
- Xgrok prototypes can also compile rc. In particular, I have successfully
- Xcompiled rc using "cc" on the sgi running IRIX-3.3.1 (version 3.2 has
- Xan older compiler---rc won't compile under that OS). I avoid using
- Xstandard header files as much as possible. In most cases, this is a
- Xwin, but you should pay attention to stddef.h and to rc.h to make
- Xsure the values there are suitable for your system.
- X
- XNote: if you have an IBM PC-RT, you *can* compile rc with IBM's
- Xcompiler but you have to tweak the sources a little. I decided not to
- Xsupport the RT because /usr/include does not have a stdarg.h, but
- Xdesperate RT users can contact me for porting info.
- X
- XIf you are on a pure system V machine, you may have define certain
- Xmacros to omit certain pieces of code. In particular, defining the
- XNOLIMITS macro will #ifdef out the Berkeley limits code.
- XAlso, the NOJOB macro if defined will omit certain calls to signal()
- Xused to make rc work on Berkeley systems that assume csh. (note that rc
- Xdoes *not* support csh-style job control in either case)
- XSimilarly, the NONMPIPES macro omits support for <{} redirection on
- Xsystems which do not support named pipes.
- X
- XFinally, on older systems without "<dirent.h>", the macro
- X"NODIRENT" must be defined. This substitutes "<sys/dir.h>" for
- X"<dirent.h>" and uses struct direct instead of struct dirent.
- X
- X------ Bugs:
- X
- XSend bug reports to byron@archone.tamu.edu. If a core dump is
- Xgenerated, sending me a backtrace will help me out a great deal. You
- Xcan get a backtrace like this:
- X
- X ; gdb rc core
- X (gdb) where
- X <<<BACKTRACE INFO>>>
- X (gdb)
- X
- XAlso, always report the machine, compiler and os used to make rc. It's
- Xpossible I may have access to a machine of that type, in which case it
- Xbecomes much easier for me to track the bug down.
- X
- X------ Man page:
- XThe man page works with nroff on my Sun, but I had to use groff in
- Xorder to get the sample code to be typeset in typewriter type. I
- Xam assuming that ditroff will also format rc.1 correctly for a
- Xprinter. If anyone can tell me how to get BSD troff to do this,
- XI would be grateful.
- X
- X------ Feeping Creaturism:
- X
- XSee the end of the man page, under "INCOMPATIBILITIES" for (known?)
- Xdifferences from the "real" rc. Most of these changes were necessary
- Xto get rc to work in a reasonable fashion on a real UNIX system; a
- Xfew were changes motivated by concern about some inadequacies in
- Xthe original design.
- X
- X------ Credits:
- X
- XThis shell was written by me, Byron Rakitzis, but kudos go to Paul
- XHaahr for letting me know what a shell should do and for contributing
- Xcertain bits and pieces to rc (notably the limits code, most of which.c
- Xand the backquote redirection code), and to Hugh Redelmeier for running
- Xrc through his fussy ANSI compiler and thereby provoking interesting
- Xdiscussions about portability, and also for providing many valuable
- Xsuggestions for improving rc's code in general. Finally, many thanks
- Xgo to David Sanderson, for reworking the man page to format well with
- Xtroff, and for providing many suggestions both for rc and its man page.
- X
- XOf course, without Tom Duff's design of the original rc, I could not
- Xhave written this shell (though I probably would have written *a*
- Xshell). Almost of all of the features, with minor exceptions, have been
- Ximplemented as described in the Unix v10 manuals. Hats off to td for
- Xdesigning a C-like, minimal but very useful shell.
- END_OF_FILE
- if test 3564 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'builtins.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'builtins.c'\"
- else
- echo shar: Extracting \"'builtins.c'\" \(10271 characters\)
- sed "s/^X//" >'builtins.c' <<'END_OF_FILE'
- X/* builtins.c: the collection of rc's builtin commands */
- X
- X#include <setjmp.h>
- X#ifndef NOLIMITS
- X#include <sys/time.h>
- X#include <sys/resource.h>
- X#endif
- X#include "rc.h"
- X#include "utils.h"
- X#include "walk.h"
- X#include "input.h"
- X#include "builtins.h"
- X#include "hash.h"
- X#include "nalloc.h"
- X#include "status.h"
- X#include "footobar.h"
- X#include "lex.h"
- X#include "open.h"
- X#include "except.h"
- X#include "redir.h"
- X#include "glom.h"
- X#include "tree.h"
- X
- Xextern int umask(int);
- X
- Xstatic void b_break(char **), b_builtin(char **), b_cd(char **),
- X b_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **),
- X b_return(char **), b_shift(char **), b_umask(char **), b_wait(char **),
- X b_whatis(char **);
- X
- Xstatic builtin_t *const builtins[] = {
- X b_break, b_builtin, b_cd, b_echo, b_eval, b_exec, b_exit,
- X b_limit, b_return, b_shift, b_umask, b_wait, b_whatis, b_dot
- X};
- X
- Xstatic char *const builtins_str[] = {
- X "break", "builtin", "cd", "echo", "eval", "exec", "exit",
- X "limit", "return", "shift", "umask", "wait", "whatis", "."
- X};
- X
- Xbuiltin_t *isbuiltin(char *s) {
- X int i;
- X
- X for (i = 0; i < arraysize(builtins_str); i++)
- X if (streq(builtins_str[i], s))
- X return builtins[i];
- X return NULL;
- X}
- X
- X/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */
- X
- Xvoid funcall(char **av) {
- X jmp_buf j;
- X Estack e1, e2;
- X
- X if (setjmp(j))
- X return;
- X
- X starassign(*av, av+1, TRUE);
- X except(RETURN, j, &e1);
- X except(STAR, NULL, &e2);
- X walk(treecpy(fnlookup(*av),nalloc), TRUE);
- X varrm("*", TRUE);
- X unexcept(); /* STAR */
- X unexcept(); /* RETURN */
- X}
- X
- X/* a dummy command. not really used to exec commands (exec() does this simply by not forking) */
- X
- Xvoid b_exec(char **av) {
- X if (av[1] == NULL) /* on a null exec, perform redirections */
- X doredirs();
- X return;
- X}
- X
- X/* echo -n omits a newline. echo -- -n echos '-n' */
- X
- Xstatic void b_echo(char **av) {
- X SIZE_T i;
- X char *format = "%a\n";
- X
- X if (*++av != NULL) {
- X if (streq(*av, "-n")) {
- X format = "%a";
- X av++;
- X } else if (streq(*av, "--")) {
- X av++;
- X }
- X }
- X
- X i = strarraylen(av) + 1; /* one for the null terminator */
- X
- X if (i < FPRINT_SIZE)
- X fprint(1, format, av);
- X else
- X writeall(1, sprint(nalloc(i), format, av), i-1);
- X set(TRUE);
- X}
- X
- X/* cd. traverse $cdpath if the directory given is not an absolute pathname */
- X
- Xstatic void b_cd(char **av) {
- X List *s, nil;
- X char *path = NULL;
- X SIZE_T t, pathlen = 0;
- X
- X if (*++av == NULL) {
- X s = varlookup("home");
- X *av = (s == NULL) ? "/" : s->w;
- X }
- X if (isabsolute(*av)) { /* absolute pathname? */
- X if (chdir(*av) < 0) {
- X set(FALSE);
- X uerror(*av);
- X } else
- X set(TRUE);
- X } else {
- X s = varlookup("cdpath");
- X if (s == NULL) {
- X s = &nil;
- X nil.w = "";
- X nil.n = NULL;
- X }
- X do {
- X if (s != &nil && *s->w != '\0') {
- X t = strlen(*av) + strlen(s->w) + 2;
- X if (t > pathlen)
- X path = nalloc(pathlen = t);
- X strcpy(path, s->w);
- X strcat(path, "/");
- X strcat(path, *av);
- X } else {
- X pathlen = 0;
- X path = *av;
- X }
- X if (chdir(path) >= 0) {
- X set(TRUE);
- X if (interactive && *s->w != '\0' && !streq(s->w,"."))
- X fprint(1,"%s\n",path);
- X return;
- X }
- X s = s->n;
- X } while (s != NULL);
- X fprint(2,"couldn't cd to %s\n", *av);
- X set(FALSE);
- X }
- X}
- X
- Xstatic void b_umask(char **av) {
- X int i;
- X
- X if (*++av == NULL) {
- X set(TRUE);
- X i = umask(0);
- X umask(i);
- X fprint(2,"0%o\n",i);
- X } else {
- X i = o2u(*av);
- X if ((unsigned int) i > 0777) {
- X set(FALSE);
- X fprint(2,"bad umask\n");
- X } else {
- X set(TRUE);
- X umask(i);
- X }
- X }
- X}
- X
- Xstatic void b_exit(char **av) {
- X int s;
- X
- X if (av[1] == NULL)
- X rc_exit(getstatus());
- X if ((s = a2u(av[1])) >= 0)
- X rc_exit(s);
- X fprint(2,"%s is a bad number\n", av[1]);
- X rc_exit(1);
- X}
- X
- X/* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */
- X
- Xstatic void b_return(char **av) {
- X int s;
- X
- X if (av[1] != NULL) {
- X s = a2u(av[1]);
- X if (s < 0) {
- X fprint(2,"%s is a bad number\n", av[1]);
- X set(FALSE);
- X } else {
- X setstatus(s << 8);
- X }
- X }
- X rc_raise(RETURN);
- X}
- X
- X/* raise a "break" exception for breaking out of for and while loops */
- X
- Xstatic void b_break(char **av) {
- X rc_raise(BREAK);
- X}
- X
- X/* shift $* n places (default 1) */
- X
- Xstatic void b_shift(char **av) {
- X int shift;
- X List *s, *dollarzero;
- X
- X shift = (av[1] == NULL ? 1 : a2u(av[1]));
- X
- X if (shift < 0) {
- X fprint(2,"%s is a bad number\n", av[1]);
- X set(FALSE);
- X return;
- X }
- X
- X s = varlookup("*")->n;
- X dollarzero = varlookup("0");
- X
- X while(s != NULL && shift != 0) {
- X s = s->n;
- X --shift;
- X }
- X
- X varassign("*", append(dollarzero, s), FALSE);
- X set(TRUE);
- X}
- X
- X/* works by advancing argv by one, really. This means that if builtin is defined as a function you are hosed */
- X
- Xstatic void b_builtin(char **av) {
- X builtin_t *b;
- X
- X if (av[1] == NULL) {
- X set(FALSE);
- X fprint(2,"no arguments to 'builtin'\n");
- X return;
- X }
- X if ((b = isbuiltin(av[1])) == NULL) {
- X set(FALSE);
- X fprint(2,"no such builtin\n");
- X } else {
- X set(TRUE);
- X b(++av);
- X }
- X}
- X
- X/* wait for a given process, or all outstanding processes */
- X
- Xstatic void b_wait(char **av) {
- X int stat, pid;
- X
- X if (av[1] == NULL) {
- X pid = wait(&stat);
- X if (pid < 0)
- X uerror("wait");
- X while(wait(&stat) >= 0)
- X ;
- X return;
- X } else {
- X pid = a2u(av[1]);
- X if (pid < 0) {
- X set(FALSE);
- X fprint(2,"%s is a bad number\n", av[1]);
- X return;
- X }
- X while (pid != wait(&stat))
- X if (pid < 0)
- X uerror("wait");
- X }
- X if (pid < 0)
- X set(FALSE);
- X else
- X setstatus(stat);
- X}
- X
- X/*
- X whatis without arguments prints all variables and functions. Otherwise, check to see if a name
- X is defined as a variable, function or pathname.
- X*/
- X
- Xstatic void b_whatis(char **av) {
- X enum bool f,found;
- X int i,j;
- X List *s,*t;
- X Node *n;
- X char *e;
- X
- X if (av[1] == NULL) {
- X whatare_all_vars();
- X set(TRUE);
- X return;
- X }
- X found = TRUE;
- X for (i = 1; av[i] != NULL; i++) {
- X f = FALSE;
- X if ((s = varlookup(av[i])) != NULL) {
- X f = TRUE;
- X fprint(1,"%s=%s", av[i], (s->n == NULL ? "" : "("));
- X for (t = s; t->n != NULL; t = t->n)
- X fprint(1,"%s ",strprint(t->w, FALSE, TRUE));
- X fprint(1,"%s%s\n",strprint(t->w, FALSE, TRUE), (s->n == NULL ? "" : ")"));
- X }
- X if ((n = fnlookup(av[i])) != NULL) {
- X f = TRUE;
- X fprint(1,"fn %s {%s}\n",av[i],ptree(n));
- X } else if (isbuiltin(av[i]) != NULL) {
- X f = TRUE;
- X for (j = 0; j < arraysize(builtins_str); j++)
- X if (streq(av[i], builtins_str[j]))
- X break;
- X fprint(1,"builtin %s\n",builtins_str[j]);
- X } else if ((e = which(av[i])) != NULL) {
- X f = TRUE;
- X fprint(1,"%s\n",e);
- X }
- X if (!f) {
- X found = FALSE;
- X fprint(2,"%s not found\n", av[i]);
- X }
- X }
- X
- X set(found);
- X}
- X
- X/* push a string to be eval'ed onto the input stack. evaluate it */
- X
- Xstatic void b_eval(char **av) {
- X boolean i = interactive;
- X
- X if (av[1] == NULL)
- X return;
- X
- X interactive = FALSE;
- X pushinput(STRING, av + 1);
- X doit(TRUE);
- X interactive = i;
- X}
- X
- X/*
- X push a file to be interpreted onto the input stack. with "-i" treat this as an interactive
- X input source.
- X*/
- X
- Xvoid b_dot(char **av) {
- X int fd;
- X boolean old_i = interactive, i = FALSE;
- X Estack e;
- X
- X av++;
- X
- X if (*av == NULL || **av == '\0')
- X return;
- X
- X if (streq(*av,"-i")) {
- X av++;
- X i = TRUE;
- X }
- X
- X if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */
- X dasheye = FALSE;
- X i = TRUE;
- X }
- X
- X fd = rc_open(*av, FROM);
- X
- X if (fd < 0) {
- X if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */
- X rcrc = FALSE;
- X else
- X uerror(*av);
- X set(FALSE);
- X return;
- X }
- X rcrc = FALSE;
- X
- X starassign(*av, av+1, TRUE);
- X pushinput(FD, fd);
- X interactive = i;
- X except(STAR, NULL, &e);
- X doit(TRUE);
- X varrm("*", TRUE);
- X unexcept(); /* STAR */
- X interactive = old_i;
- X}
- X
- X/* Berkeley limit support was cleaned up by Paul Haahr. */
- X
- X#ifdef NOLIMITS
- Xstatic void b_limit(char **av) {
- X fprint(2,"rc was compiled without berkeley limits\n");
- X set(FALSE);
- X}
- X#else
- X
- Xtypedef struct Suffix Suffix;
- Xstruct Suffix {
- X const Suffix *next;
- X long amount;
- X char *name;
- X};
- X
- Xstatic const Suffix
- X kbsuf = { NULL, 1024, "k" },
- X mbsuf = { &kbsuf, 1024*1024, "m" },
- X gbsuf = { &mbsuf, 1024*1024*1024, "g" },
- X stsuf = { NULL, 1, "s" },
- X mtsuf = { &stsuf, 60, "m" },
- X htsuf = { &mtsuf, 60*60, "h" };
- X#define SIZESUF &gbsuf
- X#define TIMESUF &htsuf
- X
- Xtypedef struct {
- X char *name;
- X int flag;
- X const Suffix *suffix;
- X} Limit;
- Xstatic const Limit limits[] = {
- X { "cputime", RLIMIT_CPU, TIMESUF },
- X { "filesize", RLIMIT_FSIZE, SIZESUF },
- X { "datasize", RLIMIT_DATA, SIZESUF },
- X { "stacksize", RLIMIT_STACK, SIZESUF },
- X { "coredumpsize", RLIMIT_CORE, SIZESUF },
- X { "memoryuse", RLIMIT_RSS, SIZESUF },
- X { NULL, 0, NULL }
- X};
- X
- Xextern int getrlimit(int, struct rlimit *);
- Xextern int setrlimit(int, struct rlimit *);
- X
- Xstatic void printlimit(const Limit *limit, boolean hard) {
- X struct rlimit rlim;
- X long lim;
- X getrlimit(limit->flag, &rlim);
- X if (hard)
- X lim = rlim.rlim_max;
- X else
- X lim = rlim.rlim_cur;
- X if (lim == RLIM_INFINITY)
- X fprint(1, "%s \tunlimited\n", limit->name);
- X else {
- X const Suffix *suf;
- X for (suf = limit->suffix; suf != NULL; suf = suf->next)
- X if (lim % suf->amount == 0) {
- X lim /= suf->amount;
- X break;
- X }
- X fprint(1, "%s \t%d%s\n", limit->name, lim, suf == NULL ? "" : suf->name);
- X }
- X}
- X
- Xstatic long parselimit(const Limit *limit, char *s) {
- X int len = strlen(s);
- X long lim = 1;
- X const Suffix *suf = limit->suffix;
- X if (streq(s, "unlimited"))
- X return RLIM_INFINITY;
- X if (suf == TIMESUF && strchr(s, ':') != NULL) {
- X char *t = strchr(s, ':');
- X *t++ = '\0';
- X lim = 60 * a2u(s) + a2u(t);
- X } else {
- X for (; suf != NULL; suf = suf->next)
- X if (streq(suf->name, s + len - strlen(suf->name))) {
- X s[len - strlen(suf->name)] = '\0';
- X lim *= suf->amount;
- X break;
- X }
- X lim *= a2u(s);
- X }
- X if (lim < 0)
- X rc_error("bad limit");
- X return lim;
- X}
- X
- Xstatic void b_limit(char **av) {
- X const Limit *lp = limits;
- X boolean hard = FALSE;
- X
- X if (*++av != NULL && streq(*av, "-h")) {
- X av++;
- X hard = TRUE;
- X }
- X
- X if (*av == NULL) {
- X for (; lp->name != NULL; lp++)
- X printlimit(lp, hard);
- X return;
- X }
- X
- X for (;; lp++) {
- X if (lp->name == NULL)
- X rc_error("no such limit");
- X if (streq(*av, lp->name))
- X break;
- X }
- X
- X if (*++av == NULL)
- X printlimit(lp, hard);
- X else {
- X struct rlimit rlim;
- X getrlimit(lp->flag, &rlim);
- X if (hard)
- X rlim.rlim_max = parselimit(lp, *av);
- X else
- X rlim.rlim_cur = parselimit(lp, *av);
- X if (setrlimit(lp->flag, &rlim) == -1)
- X uerror("setrlimit");
- X }
- X}
- X#endif
- END_OF_FILE
- if test 10271 -ne `wc -c <'builtins.c'`; then
- echo shar: \"'builtins.c'\" unpacked with wrong size!
- fi
- # end of 'builtins.c'
- fi
- if test -f 'hash.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'hash.h'\"
- else
- echo shar: Extracting \"'hash.h'\" \(1175 characters\)
- sed "s/^X//" >'hash.h' <<'END_OF_FILE'
- Xtypedef struct Function {
- X Node *def;
- X char *extdef;
- X} Function;
- X
- Xtypedef struct Variable {
- X List *def;
- X char *extdef;
- X struct Variable *n;
- X} Variable;
- X
- Xtypedef struct Htab {
- X char *name;
- X void *p;
- X} Htab;
- X
- Xextern Htab *fp, *vp;
- X
- X#define lookup_fn(s) ((Function *) lookup(s,fp))
- X#define lookup_var(s) ((Variable *) lookup(s,vp))
- X
- Xextern void *lookup(char *, Htab *);
- Xextern Function *get_fn_place(char *);
- Xextern List *varlookup(char *);
- Xextern Node *fnlookup(char *);
- Xextern Variable *get_var_place(char *, boolean);
- Xextern boolean varassign_string(char *);
- Xextern char **makeenv(void);
- Xextern char *fnlookup_string(char *);
- Xextern char *varlookup_string(char *);
- Xextern void alias(char *, List *, boolean);
- Xextern void starassign(char *, char **, boolean);
- Xextern void delete_fn(char *);
- Xextern void delete_var(char *, boolean);
- Xextern void fnassign(char *, Node *);
- Xextern void fnassign_string(char *);
- Xextern void fnrm(char *);
- Xextern void initenv(char **);
- Xextern void inithash(void);
- Xextern void setsigdefaults(void);
- Xextern void inithandler(void);
- Xextern void varassign(char *, List *, boolean);
- Xextern void varrm(char *, boolean);
- Xextern void whatare_all_vars(void);
- END_OF_FILE
- if test 1175 -ne `wc -c <'hash.h'`; then
- echo shar: \"'hash.h'\" unpacked with wrong size!
- fi
- # end of 'hash.h'
- fi
- if test -f 'rc.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rc.1'\"
- else
- echo shar: Extracting \"'rc.1'\" \(30362 characters\)
- sed "s/^X//" >'rc.1' <<'END_OF_FILE'
- X.\" rc.1
- X.\" Dd distance to space vertically before a "display"
- X.\" These are what n/troff use for interparagraph distance
- X.if t .nr Dd .4v
- X.if n .nr Dd 1v
- X.\" Ds begin a display
- X.de Ds
- X.RS \\$1
- X.sp \\n(Ddu
- X.nf
- X..
- X.\" De end a display (no trailing vertical spacing)
- X.de De
- X.fi
- X.RE
- X..
- X.ds Cf C
- X.de Cw
- X.lg 0
- X\%\&\\$3\f\\*(Cf\\$1\f1\&\\$2
- X.lg
- X..
- X.TH RC 1 "28 April 1991"
- X.SH NAME
- Xrc \- shell
- X.SH SYNOPSIS
- X.B rc
- X[
- X.B \-eixvld
- X] [
- X.B -c
- X.I command
- X] [
- X.I arguments
- X]
- X.SH DESCRIPTION
- X.I rc
- Xis a command interpreter and programming language similar to
- X.IR sh (1).
- XIt is based on the AT&T plan 9 shell of the same name.
- XThe shell offers a C-like syntax (much more so than the C shell),
- Xand a powerful mechanism for manipulating variables.
- XIt is reasonably small and reasonably fast,
- Xespecially when compared to contemporary shells.
- XIts use is intended to be interactive,
- Xbut the language lends itself well to scripts.
- X.SH OPTIONS
- X.TP
- X.B \-e
- XIf the
- X.Cw \-e
- Xoption is present, then
- X.I rc
- Xwill exit if the exit status of a command is false (nonzero).
- X.I rc
- Xwill not exit, however, if a conditional fails, e.g., an
- X.Cw if()
- Xcommand.
- X.TP
- X.B \-i
- XIf the
- X.Cw \-i
- Xoption is present or if the input to
- X.I rc
- Xis from a terminal (as determined by
- X.IR isatty (3))
- Xthen
- X.I rc
- Xwill be in
- X.I interactive
- Xmode.
- XThat is, a prompt (from
- X.Cw $prompt(1)
- Xwill be printed before an
- Xinput line is taken, and
- X.I rc
- Xwill ignore the signals
- X.Cw SIGINT
- Xand
- X.Cw SIGQUIT .
- X.TP
- X.B \-x
- XThis option will make
- X.I rc
- Xprint every command on standard error before it is executed.
- XIt can be useful for debugging
- X.I rc
- Xscripts.
- X.TP
- X.B \-v
- XThis option will echo input to
- X.I rc
- Xon standard error as it is read.
- X.TP
- X.B \-l
- XIf the
- X.Cw \-l
- Xoption is present, or if
- X.IR rc 's
- X.Cw argv[0][0]
- Xis a dash
- X.Cw - ), (
- Xthen
- X.I rc
- Xwill behave as a login shell.
- XThat is, it will try to run commands present in
- X.Cw $home/.rcrc ,
- Xif this file exists, before reading any other input.
- X.TP
- X.B \-d
- XThis flag causes
- X.I rc
- Xnot to trap
- X.Cw SIGQUIT ,
- Xand thus
- X.I rc
- Xwill dump core when it receives this signal.
- XThis option is only useful for debugging
- X.IR rc .
- X.TP
- X.B \-c
- XIf
- X.Cw \-c
- Xis present, commands are executed from the immediately following
- Xargument.
- XAny further arguments to
- X.I rc
- Xare placed in
- X.Cw $* .
- X.PP
- X.SH COMMANDS
- XA simple command is a sequence of words, separated by white space
- X(space and tab) characters that ends with a newline, semicolon
- X.Cw ; ), (
- Xor ampersand
- X.Cw & ). (
- XThe first word of a command is the name of that command.
- XIf the name begins with
- X.Cw / ,
- X.Cw ./ ,
- Xor
- X.Cw ../ ,
- Xthen the name is used as an absolute path
- Xname referring to an executable file.
- XOtherwise, the name of the command is looked up in a table
- Xof shell functions, builtin commands,
- Xor as a file in the directories named by
- X.Cw $path .
- X.SS "Background Tasks"
- XA command ending with a
- X.Cw &
- Xis run in the background; that is,
- Xthe shell returns immediately rather than waiting for the command to
- Xcomplete.
- XBackground commands have
- X.I /dev/null
- Xconnected to their standard input unless an explicit redirection for
- Xstandard input is used.
- X.SS "Subshells"
- XA command prefixed with an at-sign
- X.Cw @ ) (
- Xis executed in a subshell.
- XThis insulates the parent shell from the effects
- Xof a
- X.B cd
- Xor a variable assignment.
- XFor example:
- X.Ds
- X.Cw "@ {cd ..; make}
- X.De
- X.PP
- Xwill run
- X.IR make (1)
- Xin the parent directory
- X.Cw .. ), (
- Xbut leaves the shell running in the current directory.
- X.SS "Line continuation"
- XA long logical line may be continued over several physical lines by
- Xterminating each line (except the last) with a backslash
- X.Cw \e ). (
- XThe backslash-newline sequence is treated as a space.
- XA backslash is not otherwise special to
- X.IR rc .
- X.SS Quoting
- X.IR rc
- Xinterprets several characters specially; special characters
- Xautomatically terminate words.
- XThe following characters are special:
- X.Ds
- X.Cw "# ; & | ^ $ = ` ' { } ( ) < >\fR
- X.De
- X.PP
- XThe single quote
- X.Cw ' ) (
- Xprevents special treatment of any character other than itself.
- XAll characters, including control characters, newlines,
- Xand backslashes between two quote characters are treated as an
- Xuninterpreted string.
- XA quote character itself may be quoted by placing two quotes in a row.
- XThe minimal sequence needed to enter the quote character is
- X.Cw '''' .
- XThe empty string is represented by
- X.Cw '' .
- XThus:
- X.Ds
- X.Cw "echo 'What''s the plan, Stan?'
- X.De
- X.PP
- Xprints out
- X.Ds
- X.Cw "What's the plan, Stan?
- X.De
- X.SS Grouping
- XZero or more commands may be grouped within braces
- X.Cw { ' (`
- Xand
- X.Cw } '), `
- Xand are then treated as one command.
- XBraces do not otherwise define scope;
- Xthey are used only for command grouping.
- XIn particular, be wary of the command:
- X.Ds
- X.Cw "for (i) {
- X.Cw " command
- X.Cw "} | command
- X.De
- X.PP
- XSince pipe binds tighter than
- X.BR for ,
- Xthis command does not perform what the user expects it to.
- XInstead, enclose the whole
- X.B for
- Xstatement in braces:
- X.Ds
- X.Cw "{for (i) command} | command
- X.De
- X.PP
- XFortunately,
- X.IR rc 's
- Xgrammar is simple enough that a (confident) user can
- Xunderstand it by examining the skeletal yacc grammar
- Xat the end of this man page (see the section entitled
- XGRAMMAR).
- X.SS "Input and output"
- X.PP
- XThe standard output may be redirected to a file with
- X.Ds
- X.Cw "command > file"
- X.De
- X.PP
- Xand the standard input may be taken from a file with
- X.Ds
- X.Cw "command < file
- X.De
- X.PP
- XFile descriptors other than 0 and 1 may be specified also.
- XFor example, to redirect standard error to a file, use:
- X.Ds
- X.Cw "command >[2] file
- X.De
- X.PP
- XIn order to duplicate a file descriptor, use
- X\f\*(Cf>[\fIn\f\*(Cf=\fIm\f\*(Cf]\fR.
- XThus to redirect both standard output and standard error
- Xto the same file, use
- X.Ds
- X.Cw "command > file >[2=1]
- X.De
- X.PP
- XTo close a file descriptor that may be open, use
- X\f\*(Cf>[\fIn\f\*(Cf=]\fR.
- XFor example, to
- Xclose file-descriptor 7:
- X.Ds
- X.Cw "command >[7=]
- X.De
- X.PP
- XIn order to place the output of a command at the end of an already
- Xexisting file, use:
- X.Ds
- X.Cw "command >> file
- X.De
- X.PP
- XIf the file does not exist, then it is created.
- X.PP
- X``Here documents'' are supported as in
- X.IR sh (1)
- Xwith the use of
- X.Ds
- X.Cw "command << 'eof-marker'
- X.De
- X.PP
- XIf the end-of-file marker is enclosed in quotes, then no variable substitution
- Xoccurs inside the here document.
- XOtherwise, every variable is
- Xsubstituted by its space-separated-list value (see Flat Lists, below),
- Xand if a
- X.Cw ^
- Xcharacter follows a variable name, it is deleted.
- XThis allows the unambiguous use of variables adjacent to text, as in
- X.Ds
- X.Cw $variable^follow
- X.De
- X.PP
- XAdditionally,
- X.I rc
- Xsupports ``here strings'', which are like here documents, except that input
- Xis taken directly from a string on the command line. Its use is illustrated
- Xhere:
- X.Ds
- X.Cw "cat <<< 'this is a here string' | wc
- X.De
- X.PP
- X(This feature enables
- X.I rc
- Xto export functions using here documents into the environment; the author
- Xdoes not expect users to find this feature useful.)
- X.SS Pipes
- XTwo or more commands may be combined in a pipeline by placing the
- Xvertical bar
- X.Cw | ) (
- Xbetween them.
- XThe standard output (file descriptor 1)
- Xof the command on the left is tied to the standard input (file
- Xdescriptor 0) of the command on the right.
- XThe notation
- X\f\*(Cf|[\fIn\f\*(Cf=\fIm\f\*(Cf]\fR
- Xindicates that file descriptor
- X.I n
- Xof the left process is connected to
- Xfile descriptor
- X.I m
- Xof the right process.
- X\f\*(Cf|[\fIn\f\*(Cf]\fR
- Xis a shorthand for
- X\f\*(Cf|[\fIn\f\*(Cf=0]\fR.
- XAs an example, to pipe the standard error of a command to
- X.IR wc (1),
- Xuse:
- X.Ds
- X.Cw "command |[2] wc
- X.De
- X.SS "Commands as Arguments"
- XSome commands, like
- X.IR cmp (1)
- Xor
- X.IR diff (1),
- Xtake their arguments on the command
- Xline, and do not read input from standard input.
- XIt is convenient
- Xsometimes to build nonlinear pipelines so that a command like cmp can
- Xread the output of two other commands at once.
- X.I rc
- Xdoes it like this:
- X.Ds
- X.Cw "cmp <{command} <{command}
- X.De
- X.PP
- Xcompares the output of the two commands in braces.
- XA note: since this form of
- Xredirection is implemented with named pipes, and since one cannot
- X.IR lseek (2)
- Xon a pipe, commands that use
- X.IR lseek (2)
- Xwill hang.
- XFor example,
- Xmost versions of
- X.IR diff (1)
- Xuse
- X.IR lseek (2)
- Xon their inputs.
- X.SH "CONTROL STRUCTURES"
- XThe following may be used for control flow in
- X.IR rc :
- X.SS "If-else Statements"
- X.PD 0
- X.sp
- X\fBif (\fItest\fB) {
- X.br
- X.B " " \fIcmd\fB
- X.br
- X.TP
- X.B } else \fIcmd\fB
- XThe
- X.I test
- Xis executed, and if its return status is zero, the first
- Xcommand is executed, otherwise the second is.
- XBraces are not mandatory around the commands.
- XHowever, an else statement is valid only if it
- Xfollows a close-brace on the same line.
- XOtherwise, the if is taken to be a simple-if:
- X.Ds
- X.Cw "if (test)
- X.Cw " command
- X.De
- X.PD
- X.SS "While and For Loops"
- X.TP
- X.B while (\fItest\fB) \fIcmd\fB
- X.I rc
- Xexecutes the
- X.I test
- Xand performs the command as long as the
- X.I test
- Xis true.
- X.TP
- X.B for (\fIvar\fB in \fIlist\fB) \fIcmd\fB
- X.I rc
- Xsets
- X.I var
- Xto each element of
- X.I list
- X(which may contain variables and backquote substitutions) and runs
- X.IR cmd .
- XIf ``\fBin\fR \fIlist\fR'' is omitted, then
- X.I rc
- Xwill set
- X.I var
- Xto each element of
- X.Cw $*
- X(excluding
- X.Cw $0 .
- XFor example:
- X.Ds
- X.Cw "for (i in `{ls -F | grep '\e*$' | sed 's/\e*$//'}) { commands }
- X.De
- X.PP
- Xwill set
- X.Cw $i
- Xto the name of each file in the current directory which is
- Xexecutable.
- X.SS "Switch"
- X.TP
- X.B switch (\fIlist\fB) { case \fR...\fB }
- X.I rc
- Xlooks inside the braces after a
- X.B switch
- Xstatement for single lines beginning with the word
- X.BR case .
- XIf any of the patterns following
- X.B case
- Xmatch the list supplied to
- X.BR switch ,
- Xthen the commands up until the next
- X.B case
- Xstatement are executed.
- XMetacharacters should not be quoted;
- Xmatching is performed only against the strings in
- X.IR list ,
- Xnot against file names.
- X(Matching for case statements is the same as for the
- X.Cw ~
- Xcommand.)
- X.SS "Logical Operators"
- XThere are a number of operators in
- X.I rc
- Xwhich depend on the exit status of a command.
- X.Ds
- X.Cw "command && command
- X.De
- X.PP
- Xexecutes the first command and then executes the second command if and only if
- Xthe first command exits with a zero exit status (``true'' in UNIX).
- X.Ds
- X.Cw "command || command
- X.De
- X.PP
- Xexecutes the first command executing the second command if and only if
- Xthe second command exits with a nonzero exit status (``false'' in UNIX).
- X.Ds
- X.Cw "! command
- X.De
- X.PP
- Xnegates the exit status of a command.
- XThus:
- X.Ds
- X.Cw "! command || command
- X.De
- X.PP
- Xis equivalent to
- X.Ds
- X.Cw "command && command
- X.De
- X.SH "PATTERN MATCHING"
- XThere are two forms of pattern matching in
- X.IR rc .
- XOne is traditional shell globbing.
- XThis occurs in matching for file names in argument lists:
- X.Ds
- X.Cw "command argument argument ...
- X.De
- X.PP
- XWhen the characters
- X.Cw "*" ,
- X.Cw [
- Xor
- X.Cw ?
- Xoccur in an argument,
- X.I rc
- Xlooks at the
- Xargument as a pattern for matching against files according to the
- Xfollowing rules: a
- X.Cw *
- Xmatches any number (including zero) of
- Xcharacters.
- XA
- X.Cw ?
- Xmatches any single character, and a
- X.Cw [
- Xfollowed by a
- Xnumber of characters followed by a
- X.Cw ]
- Xmatches a single character in that
- Xclass.
- XThe rules for character class matching are the same as those for
- X.IR ed (1),
- Xwith the exception that character class negation is achieved
- Xwith the tilde
- X.Cw ~ ), (
- Xnot the caret
- X.Cw ^ ), (
- Xsince the caret already means
- Xsomething else in
- X.IR rc .
- X.PP
- X.I rc
- Xalso matches patterns against strings with the
- X.Cw ~
- Xcommand:
- X.Ds
- X.Cw "~ subject pattern pattern ...
- X.De
- X.PP
- X.Cw ~
- Xsets
- X.Cw $status
- Xto zero if and only if a supplied pattern matches any
- Xsingle element of the subject list.
- XThus
- X.Ds
- X.Cw "~ foo f*
- X.De
- X.PP
- Xsets status to zero, while
- X.Ds
- X.Cw "~ (bar baz) f*
- X.De
- X.PP
- Xsets status to one.
- XThe null list is matched by the null list, so
- X.Ds
- X.Cw "~ $foo ()
- X.De
- X.PP
- Xchecks to see whether
- X.Cw $foo
- Xis empty or not.
- XThis may also be achieved
- Xby the test
- X.Ds
- X.Cw "~ $#foo 0
- X.De
- X.PP
- XNote that inside a
- X.Cw ~
- Xcommand
- X.I rc
- Xdoes not match patterns against file
- Xnames, so it is not necessary to quote the characters
- X.Cw "*" ,
- X.Cw [
- Xand
- X.Cw "?" .
- XFinally, note that if the
- X.Cw ~
- Xcommand is given a list as its first
- Xargument, then a successful match against any of the elements of that
- Xlist will cause
- X.Cw ~
- Xto return true.
- XFor example:
- X.Ds
- X.Cw "~ (foo goo zoo) z*
- X.De
- X.PP
- Xis true.
- X.SH "LISTS AND VARIABLES"
- XThe primary data structure in
- X.IR rc
- Xis the list, which is a sequence of words.
- XParentheses are used to group lists.
- XThe empty list is represented by
- X.Cw "()" .
- XLists have no hierarchical structure;
- Xa list inside another list is expanded so the
- Xouter list contains all the elements of the inner list.
- XThus, the following are all equivalent
- X.Ds
- X.Cw "one two three
- X
- X.Cw "(one two three)
- X
- X.Cw "((one) () ((two three)))
- X.De
- X.PP
- XNote that the null string,
- X.Cw "''" ,
- Xand the null list,
- X.Cw "()" ,
- Xare two very
- Xdifferent things.
- XAssigning the null string to variable is a valid
- Xoperation, but it does not remove its definition.
- XFor example,
- Xif
- X.Cw $a
- Xis set to
- X.Cw "''" ,
- Xthen
- X.Cw "$#a" ,
- Xreturns a 1.
- X.SS "List Concatenation"
- XTwo lists may be joined by the concatenation operator
- X.Cw ^ ). (
- XA single word is treated as a list of length one, so
- X.Ds
- X.Cw "echo foo^bar
- X.De
- X.PP
- Xproduces the output
- X.Ds
- X.Cw foobar
- X.De
- X.PP
- XFor lists of more than one element,
- Xconcatenation works according to the following rules: if the two lists
- Xhave the same number of elements, then concatenation is pairwise:
- X.Ds
- X.Cw "echo (a\- b\- c\-)^(1 2 3)
- X.De
- X.PP
- Xproduces the output
- X.Ds
- X.Cw "a\-1 b\-2 c\-3
- X.De
- X.PP
- XOtherwise, one of the lists must have a single element, and then the
- Xconcatenation is distributive:
- X.Ds
- X.Cw "cc \-^(O g c) (malloc alloca)^.c
- X.De
- X.PP
- Xhas the effect of performing the command
- X.Ds
- X.Cw "cc \-O \-g \-c malloc.c alloca.c
- X.De
- X.SS "Free Carets"
- X.I rc
- Xinserts carets (concatenation operators) for free in certain
- Xsituations, in order to save some typing on the user's behalf.
- XFor
- Xexample, the above example could also be typed in as:
- X.Ds
- X.Cw "opts=(O g c) files=(malloc alloca) cc \-$opts $files.c
- X.De
- X.PP
- X.I rc
- Xtakes care to insert a free-caret between the
- X.Cw \- ' `
- Xand
- X.Cw "$opts" ,
- Xas well
- Xas between
- X.Cw $files
- Xand
- X.Cw ".c" .
- XThe rule for free carets is as follows: if
- Xa word or keyword is immediately
- Xfollowed by another word, keyword, dollar-sign or
- Xbackquote, then
- X.I rc
- Xinserts a caret between them.
- X.SS "Variables"
- XA list may be assigned to a variable, using the notation:
- X.Ds
- X.Cw "var = list
- X.De
- X.PP
- XAny sequence of non-special characters, except a sequence including
- Xonly digits, may be used as a variable name.
- XAll user-defined variables are exported into the environment.
- X.PP
- XThe value of a variable is referenced with the notation:
- X.Ds
- X.Cw $var
- X.De
- X.PP
- XAny variable which has not been assigned a value returns the null list,
- X.Cw "()" ,
- Xwhen referenced. In addition, multiple references are allowed:
- X.Ds
- X.Cw a=foo
- X.Cw b=a
- X.Cw echo $$b
- X.De
- X.PP
- Xprints
- X.Ds
- X.Cw foo
- X.De
- X.PP
- XA variable's definition may also be removed by
- Xassigning the null list to a variable:
- X.Ds
- X.Cw var=()
- X.De
- X.PP
- XFor ``free careting'' to work correctly,
- X.I rc
- Xmust make certain assumptions
- Xabout what characters may appear in a variable name.
- X.I rc
- Xcurrently
- Xassumes that a variable name consists only of alphanumeric characters,
- Xunderscore
- X.Cw _ ) (
- Xand star
- X.Cw * ). (
- XTo reference a variable with other
- Xcharacters in its name, quote the variable name.
- XThus:
- X.Ds
- X.Cw "echo $'we$Ird\Variab!le'
- X.De
- X.SS "Local Variables"
- XAny number of variable assignments may be made local to a single
- Xcommand by typing:
- X.Ds
- X.Cw "a=foo b=bar ... command
- X.De
- X.PP
- XThe command may be a compound command, so for example:
- X.Ds
- X.Cw "path=. ifs=() {
- X.Cw ...
- X.De
- X.PP
- Xsets path to
- X.Cw .
- Xand ifs to
- X.Cw ()
- Xfor the duration of one long compound
- Xcommand.
- X.SS "Variable Subscripts"
- XVariables may be subscripted with the notation
- X.Ds
- X\f\*(Cf$var(\fIn\f\*(Cf\fR)
- X.De
- X.PP
- Xwhere
- X.I n
- Xis a list of integers (origin 1).
- XThe list of subscripts need
- Xnot be in order or even unique.
- XThus, if
- X.Ds
- X.Cw "a=(one two three)
- X.De
- X.PP
- Xthen
- X.Ds
- X.Cw "echo $a(3 3 3)
- X.De
- X.PP
- Xprints
- X.Ds
- X.Cw "three three three
- X.De
- X.PP
- XIf
- X.I n
- Xreferences a nonexistent element, then
- X\f\*(Cf$var(\fIn\f\*(Cf\fR)
- Xreturns the null
- Xlist.
- XThe notation
- X.Cw "$\fIn" ,
- Xwhere
- X.I n
- Xis an integer, is a shorthand for
- X\f\*(Cf$*(\fIn\f\*(Cf)\fR.
- XThus,
- X.IR rc 's
- Xarguments may be referred to as
- X.Cw "$1" ,
- X.Cw "$2" ,
- Xand so on.
- X.PP
- XNote also that the list of subscripts may be given by any of
- X.IR rc 's
- Xlist operations:
- X.Ds
- X.Cw "$var(`{awk 'BEGIN{for(i=1;i<=10;i++)print i;exit; }'})
- X.De
- X.PP
- Xreturns the first 10 elements of
- X.Cw $var .
- X.PP
- XTo count the number of elements in a variable, use
- X.Ds
- X.Cw $#var
- X.De
- X.PP
- XThis returns a single-element list, with the number of elements in
- X.Cw $var .
- X.SS "Flat Lists"
- XIn order to create a single-element list from a multi-element list,
- Xwith the components space-separated, use
- X.Ds
- X.Cw $^var
- X.De
- X.PP
- XThis is useful when the normal list concatenation rules need to be
- Xbypassed.
- XFor example, to append a single period at the end of
- X.Cw $path ,
- Xuse:
- X.Ds
- X.Cw "echo $^path.
- X.De
- X.SS "Backquote Substitution"
- XA list may be formed from the output of a command by using backquote
- Xsubstitution:
- X.Ds
- X.Cw "`{ command }
- X.De
- X.PP
- Xreturns a list formed from the standard output of the command in braces.
- X.Cw $ifs
- Xis used to split the output into list elements.
- XBy default,
- X.Cw $ifs
- Xhas the value space-tab-newline.
- XThe braces may be omitted if the command is a single word.
- XThus
- X.Cw `ls
- Xmay be used instead of
- X.Cw "`{ls}" .
- XThis last feature is useful when defining functions that expand
- Xto useful argument lists. A frequent use is:
- X.Ds
- X.Cw "fn src { echo *.[chy] }
- X.De
- X.PP
- Xfollowed by
- X.Ds
- X.Cw "wc `src
- X.De
- X.PP
- X(This will print out a word-count of all C source files in the current
- Xdirectory.)
- X.PP
- XIn order to override the value of
- X.Cw $ifs
- Xfor a single backquote
- Xsubstitution, use:
- X.Ds
- X.Cw "`` (ifs-list) { command }
- X.De
- X.PP
- X.Cw $ifs
- Xwill be temporarily ignored and the command's output will be split as specified by
- Xthe list following the double backquote.
- XFor example:
- X.Ds
- X.Cw "`` ($nl :) {cat /etc/passwd}
- X.De
- X.PP
- Xsplits up
- X.I /etc/passwd
- Xinto fields, assuming that
- X.Cw $nl
- Xcontains a newline
- Xas its value.
- X.SH "SPECIAL VARIABLES"
- XSeveral variables are known to
- X.I rc
- Xand are treated specially.
- X.TP
- X.B *
- XThe argument list of
- X.IR rc .
- X.Cw "$1, $2,
- Xetc. are the same as
- X.Cw $*(1) ,
- X.Cw $*(2) ,
- Xetc.
- XThe variable
- X.Cw $0
- Xholds the value of
- X.Cw argv[0]
- Xwith which
- X.I rc
- Xwas invoked.
- XAdditionally,
- X.Cw $0
- Xis set to the name of a function for the duration of
- Xthe execution of that function, and
- X.Cw $0
- Xis also set to the name of the
- Xfile being interpreted for the duration of a
- X.Cw .
- Xcommand.
- X.TP
- X.B apid
- XThe process ID of the last process started in the background.
- X.TP
- X.B cdpath
- XA list of directories to search for the target of a
- X.B cd
- Xcommand.
- XThe empty string stands for the current directory. Note that
- Xan assignment to
- X.Cw $cdpath
- Xcauses an automatic assignment to
- X.Cw $CDPATH ,
- Xand vice-versa
- X.TP
- X.B history
- X.Cw $history
- Xcontains the name of a file to which commands are appended as
- X.I rc
- Xreads them.
- XThis facilitates the use of a stand-alone history program
- Xwhich parses the contents of the history file and presents them to
- X.I rc
- Xfor reinterpretation.
- XIf
- X.Cw $history
- Xis not set, then
- X.I rc
- Xdoes not append commands to any file.
- X.TP
- X.B home
- XThe default directory for the builtin cd command and is the directory
- Xin which
- X.I rc
- Xlooks to find its initialization file,
- X.IR .rcrc ,
- Xif
- X.I rc
- Xhas been started up as a login shell. Like
- X.Cw $cdpath
- Xand
- X.Cw $CDPATH ,
- X.Cw $home
- Xand
- X.Cw $HOME
- Xare aliased to each other.
- X.TP
- X.B ifs
- XThe internal field separator, used for splitting up the output of
- Xbackquote commands for digestion as a list.
- X.TP
- X.B path
- XThis is a list of directories to search in for commands.
- XThe empty string stands for the current directory. Note that
- Xlike
- X.Cw $cdpath
- Xand
- X.Cw $CDPATH ,
- X.Cw $path
- Xand
- X.Cw $PATH
- Xare aliased to each other.
- X.TP
- X.B pid
- XThe process ID of the currently running
- X.IR rc .
- X.TP
- X.B prompt
- XThis variable holds the two prompts (in list form, of course) that
- X.I rc
- Xprints.
- X.Cw $prompt(1)
- Xis printed before each command is read, and
- X.Cw $prompt(2)
- Xis printed when input is expected to continue on the next
- Xline.
- X.I rc
- Xsets
- X.Cw $prompt
- Xto
- X.Cw "('; ' '')
- Xby default.
- XThe reason for this is that it enables an
- X.I rc
- Xuser to grab commands from previous lines using a
- Xmouse, and to present them to
- X.I rc
- Xfor re-interpretation; the semicolon
- Xprompt is simply ignored by
- X.IR rc .
- XThe null
- X.Cw $prompt(2)
- Xalso has its
- Xjustification: an
- X.I rc
- Xscript, when typed interactively, will not leave
- X.Cw $prompt(2) 's
- Xon the screen,
- Xand can therefore be grabbed by a mouse and placed
- Xdirectly into a file for use as a shell script, without further editing
- Xbeing necessary.
- X.TP
- X.B prompt (function)
- XIf this function is set, then it gets executed every time
- X.I rc
- Xis about to print
- X.Cw "$prompt(1)" .
- X.TP
- X.B status
- XThe exit status of the last command.
- XIf the command exited with a numeric value,
- Xthat number is the status.
- XIf the died with a signal,
- Xthe status is the name of that signal; if a core file
- Xwas created, the string
- X.Cw +core '' ``
- Xis appended.
- XThe value of
- X.Cw $status
- Xfor a pipeline is a list, with one entry,
- Xas above, for each process in the pipeline.
- XFor example, the command
- X.Ds 1i
- X.Cw "ls | wc
- X.De
- X.TP
- X\&
- Xusually sets
- X.Cw $status
- Xto
- X.Cw "(0 0)" .
- X.PP
- XThe values of
- X.Cw "$path" ,
- X.Cw "$cdpath" ,
- Xand
- X.Cw $home
- Xare derived from the environment
- Xvalues of
- X.Cw "$PATH" ,
- X.Cw "$CDPATH" ,
- Xand
- X.Cw "$HOME" .
- XOtherwise, they are derived from
- Xthe environment values of
- X.Cw $path ,
- X.Cw $cdpath
- Xand
- X.Cw $home .
- XThis is for compatibility with other UNIX programs, like
- X.IR sh (1).
- X.Cw $PATH
- Xand
- X.Cw $CDPATH
- Xare assumed to be colon-separated lists.
- X.SH FUNCTIONS
- X.I rc
- Xfunctions are identical to
- X.I rc
- Xscripts, except that they are stored
- Xin memory and are automatically exported into the environment.
- XA shell function is declared as:
- X.Ds
- X.Cw "fn name { commands }
- X.De
- X.PP
- X.I rc
- Xscans the definition in until the close-brace, so the function can
- Xspan more than one line.
- XThe function definition may be removed by typing
- X.Ds
- X.Cw "fn name
- X.De
- X.PP
- XWhen a function is executed,
- X.Cw $*
- Xis set to the arguments to that
- Xfunction for the duration of the command.
- XThus a reasonable definition for
- X.Cw "l" ,
- Xa shorthand for
- X.IR ls (1),
- Xcould be:
- X.Ds
- X.Cw "fn l { ls -FC $* }
- X.De
- X.PP
- Xbut not
- X.Ds
- X.Cw "fn l { ls -FC }
- X.De
- X.SH "INTERRUPTS AND SIGNALS"
- X.I rc
- Xrecognizes a number of signals, and allows the user to define shell
- Xfunctions which act as signal handlers.
- X.I rc
- Xby default traps
- X.Cw SIGINT
- Xand
- X.Cw SIGQUIT
- Xwhen it is interactive mode.
- X.Cw SIGQUIT
- Xis ignored, unless
- X.I rc
- Xhas been invoked with the
- X.Cw \-d
- Xflag.
- XHowever, user-defined signal handlers may be written for these and
- Xall other signals.
- XThe way to define a signal handler is to
- Xwrite a function by the name of the signal in lower case.
- XThus:
- X.Ds
- X.Cw "fn sighup { echo hangup; rm /tmp/rc$pid.*; exit }
- X.De
- X.PP
- XIn addition to Unix signals, rc recognizes the artificial signal
- X.Cw SIGEXIT
- Xwhich occurs as rc is about to exit.
- X.PP
- XIn order to remove a signal handler's definition, remove it as though
- Xit were a regular function.
- XFor example:
- X.Ds
- X.Cw "fn sigint
- X.De
- X.PP
- Xreturns the handler of
- X.Cw SIGINT
- Xto the default value.
- XIn order to ignore a signal, set the signal handler's value to
- X.Cw "{}" .
- XThus:
- X.Ds
- X.Cw "fn sigint {}
- X.De
- X.PP
- Xcauses SIGINT to be ignored by the shell.
- X.SH "BUILTIN COMMANDS"
- XBuiltin commands execute in the context of the shell, but otherwise
- Xbehave exactly like other commands.
- X.TP
- X.B . \fR[\fB\-i\fR]\fB \fIfile args\fB
- XReads \fIfile\fP as input to
- X.IR rc
- Xand executes its contents.
- XWith a
- X.Cw \-i
- Xflag, input is interactive.
- XThus
- Xfrom within a shell script,
- X.Ds 1i
- X.Cw ". \-i /dev/tty
- X.De
- X.TP
- X\&
- Xdoes the ``right'' thing.
- X.TP
- X.B break
- XBreaks from the innermost
- X.B for
- Xor
- X.BR while ,
- Xas in C.
- XIt is an error to
- Xinvoke
- X.B break
- Xoutside of a loop.
- X(Note that
- Xthere is no
- X.B break
- Xkeyword between
- Xcommands in
- X.B switch
- Xstatements, unlike C.)
- X.TP
- X.B builtin \fIcommand ...\fB
- XExecutes the command as a builtin; no function lookup or directory
- Xsearching is done.
- XThis command is present to allow functions with the
- Xsame names as builtins to use the underlying builtin.
- X.TP
- X.B cd \fIdirectory\fB
- XChange the current directory.
- XThe variable
- X.Cw $cdpath
- Xis searched for
- Xpossible locations of \fIdirectory\fP, analogous to the searching of
- X.Cw $path
- Xfor executable files.
- XWith no argument,
- X.B cd
- Xchanges directory to
- X.Cw "$home" .
- X.TP
- X.B echo \fIargs ...\fB
- XPrints its arguments to standard output.
- XArguments are separated by spaces.
- XIf the first argument is
- X.Cw "\-n" ,
- Xno final newline is printed.
- XIf the first argument is
- X.Cw "\-\-" ,
- Xthen any subsequent arguments are ignored.
- X.TP
- X.B eval \fIlist\fB
- X.B eval
- Xconcatenates the elements of
- X.I list
- Xwith spaces and feeds the resulting string to
- X.I rc
- Xfor re-scanning.
- XThis is the only time input is rescanned in
- X.IR rc .
- X.TP
- X.B exec \fIcommand\fB
- Xreplaces
- X.I rc
- Xwith the given command.
- XIf the exec contains only redirections,
- Xthen these redirections apply to the current shell
- Xand the shell does not exit.
- XFor example,
- X.Ds 1i
- X.Cw "exec >[2] err.out
- X.De
- X.TP
- X\&
- Xplaces further output to standard error in the file
- X.IR err.out .
- X.TP
- X.B exit \fIstatus\fB
- XCause the current shell to exit with the given exit
- X.IR status .
- XIf no argument is given, the current value of
- X.Cw $status
- Xis used.
- X.TP
- X.B limit \fR[\fB\-h\fR]\fB \fR[\fIresource\fR]\fB \fR[\fIvalue\fR]\fB
- XSimilar to the
- X.IR csh (1)
- Xlimit builtin, this command operates upon the
- XBSD-style limits of a process.
- XThe
- X.Cw \-h
- Xflag displays/alters the hard
- Xlimits.
- XThe resources which can be shown or altered are
- X.BR cputime ,
- X.BR filesize ,
- X.BR datasize ,
- X.BR stacksize ,
- X.B coredumpsize
- Xand
- X.BR memoryuse .
- XFor
- Xexample:
- X.Ds 1i
- X.Cw "limit coredumpsize 0
- X.De
- X.TP
- X\&
- Xdisables core dumps.
- X.TP
- X.B return \fIn\fB
- XReturns from the current function, with status
- X.IR n .
- XIf
- X.IR n
- Xis omitted, then
- X.Cw $status
- Xis left unchanged.
- XIt is an error to invoke
- X.B return
- Xwhen not inside a function.
- X.TP
- X.B shift \fIn\fB
- XDeletes
- X.I n
- Xelements from the beginning of
- X.Cw $*
- Xand shifts the other
- Xelements down by
- X.IR n .
- X.I n
- Xdefaults to 1.
- X(Note that
- X.Cw $0
- Xis not affected by
- X.BR shift .)
- X.TP
- X.B umask \fImask\fB
- XSets the current umask (see
- X.IR umask (2))
- Xto the octal
- X.IR mask .
- XIf no argument is present, the current mask value is printed.
- X.TP
- X.B wait \fIpid\fB
- XWaits for the specified
- X.IR pid ,
- Xwhich must have been started by
- X.IR rc .
- XIf no
- X.I pid
- Xis specified,
- X.I rc
- Xwaits for any child process to exit.
- X.TP
- X.B whatis \fIname ...\fB
- XPrints a definition of the named objects.
- XFor variables, their values
- Xare printed; for functions, their definitions are; and for executable
- Xfiles, path names are printed.
- XWithout arguments,
- X.B whatis
- Xprints the values of all shell variables and functions. Note that
- X.B whatis
- Xoutput is suitable for input to
- X.IR rc ;
- Xby saving the output of
- X.B whatis
- Xin a file, it should be possible to recreate the state of
- X.I rc
- Xby sourcing this file with a
- X.Cw .
- Xcommand.
- X.SH GRAMMAR
- XHere is
- X.IR rc 's
- Xgrammar, edited to remove semantic actions.
- X.Ds
- X\f\*(Cf
- X%term BANG DUP ELSE END FN FOR HUH IF IN LBRACK PIPE RBRACK
- X%term REDIR STAR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD
- X
- X%left IF WHILE FOR SWITCH ')' ELSE
- X%left ANDAND OROR
- X%left BANG SUBSHELL
- X%left PIPE
- X%left '^'
- X%right '$' COUNT FLAT
- X%left SUB
- X%left '`' BACKBACK
- X
- X%%
- X
- Xrc: line end | error end
- X
- Xend: '\en' | END
- X
- Xcmdsa: cmd ';' | cmd '&'
- X
- Xline: cmd | cmdsa line
- X
- Xbody: cmd | cmdsan body
- X
- Xcmdsan: cmdsa | cmd '\en'
- X
- Xbrace: '{' body '}'
- X
- Xparen: '(' body ')'
- X
- Xassign: first '=' word
- X
- Xepilog: /* empty */ | redir epilog
- X
- Xredir: DUP | REDIR word
- X
- Xiftail: cmd %prec IF | brace ELSE cmd
- X
- Xcmd : /* empty */
- X | simple
- X | brace epilog
- X | IF paren { skipnl(); } iftail
- X | FOR '(' word IN words ')' { skipnl(); } cmd
- X | FOR '(' word ')' { skipnl(); } cmd
- X | WHILE paren { skipnl(); } cmd
- X | SWITCH '(' word ')' { skipnl(); } brace
- X | TWIDDLE word words
- X | cmd ANDAND { skipnl(); } cmd
- X | cmd OROR { skipnl(); } cmd
- X | cmd PIPE { skipnl(); } cmd
- X | redir cmd %prec BANG
- X | assign cmd %prec BANG
- X | BANG cmd
- X | SUBSHELL cmd
- X | FN words brace
- X | FN words
- X
- Xsimple: first | simple word | simple redir
- X
- Xfirst: comword | first '^' word
- X
- Xword: comword | keyword | word '^' word
- X
- Xcomword: WORD
- X | COUNT word | FLAT word
- X | '`' word | '`' brace
- X | BACKBACK word brace | BACKBACK word word
- X | '(' words ')'
- X | REDIR brace
- X | '$' word | '$' word SUB words ')'
- X
- Xkeyword: FOR | IN | WHILE | IF | SWITCH
- X | FN | ELSE | TWIDDLE | BANG | SUBSHELL
- X
- Xwords: /* empty */ | words word
- X\fR
- X.De
- X.SH FILES
- X.I "$HOME/.rcrc, /tmp/rc*, /dev/null
- X.SH CREDITS
- X.I rc
- Xwas written by Byron Rakitzis, with valuable help
- Xfrom Paul Haahr, Hugh Redelmeier and David Sanderson.
- XThe design of this shell has been copied from the rc
- Xthat Tom Duff wrote at Bell Labs.
- X.SH BUGS
- X.Cw <{foo}
- Xstyle redirection is implemented with named pipes, and it is sometimes
- Xpossible to foil rc into removing the FIFO it places in
- X.I /tmp
- Xprematurely, or it is even possible to cause rc to hang. This redirection
- Xshould be implemented via
- X.I /dev/fd
- Xon systems which have it.
- X.B
- XThe functionality of
- X.B shift
- Xshould be available for variables other than
- X.Cw "$*" .
- X.PP
- X.B echo
- Xis built in only for performance reasons, which is a bad idea.
- X.PP
- XThere should be a way to avoid exporting a variable.
- X.PP
- XThe
- X.Cw $^var
- Xnotation for flattening should allow for using an arbitrary
- Xseparating character, not just space.
- X.PP
- XBug reports should be mailed to
- X.Cw "byron@archone.tamu.edu" .
- X.SH INCOMPATIBILITIES
- XHere is a list of features which distinguish this incarnation of
- X.I rc
- Xfrom the one described in the Bell Labs manual pages:
- X.PP
- XThe treatment of if-else is different in the v10
- X.IR rc :
- Xthat version uses
- Xan ``if not'' clause which gets executed if the preceding ``if'' test
- Xdoes not succeed.
- X.PP
- XBackquotes are slightly different in v10
- X.IR rc :
- Xa backquote must always be followed by
- Xa left-brace.
- XThis restriction is not present for single-word
- Xcommands in this
- X.IR rc .
- X.PP
- XThe following are all new with this version of
- X.IR rc :
- XThe list flattening operator,
- Xhere strings (they facilitate exporting of functions
- Xwith here documents into the environment),
- Xthe
- X.B return
- Xand
- X.B break
- Xkeywords,
- Xthe
- X.B echo
- Xbuiltin,
- Xthe support for the GNU
- X.IR readline (3)
- Xlibrary and
- Xthe support for the
- X.B prompt
- Xfunction.
- XThis
- X.I rc
- Xalso sets
- X.Cw $0
- Xto the name of a function being executed/file
- Xbeing sourced.
- X.SH "SEE ALSO"
- X``rc \(em A shell for Plan 9 and UNIX'',
- XUnix Research System,
- X10th Edition,
- Xvol. 2. (Saunders College Publishing)
- END_OF_FILE
- if test 30362 -ne `wc -c <'rc.1'`; then
- echo shar: \"'rc.1'\" unpacked with wrong size!
- fi
- # end of 'rc.1'
- fi
- echo shar: End of archive 1 \(of 4\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-